﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Remoting.Messaging;
using System.Text;
using Dapper;
using ProjetoSolo.QueroGas.Dominio.Entidades;
using ProjetoSolo.QueroGas.Dominio.Repositorios;
using ProjetoSolo.QueroGas.Infraestrutura.PersistenciaAdo.Extensions;
using ProjetoSolo.QueroGas.Infraestrutura.Validacao;

namespace ProjetoSolo.QueroGas.Infraestrutura.PersistenciaAdo.Repositorios
{
    public class RepositorioUsuario : IRepositorioUsuario
    {
        private readonly ContextoAdo contexto;

        public RepositorioUsuario(IContextoRepositorio contexto)
        {
            RegraValidacao.VerificarObjetoNulo(contexto, "O contexto não pode ser nulo.");

            this.contexto = (ContextoAdo)contexto;
        }
       
        public int Cadastrar(Usuario usuario)
        {
            StringBuilder query = new StringBuilder();
            query.Append("insert into Usuario output inserted.IdUsuario values(@Nome, @Senha, @UltimoLogin, @Email, @Ativo, @DataCadastro)");

            return this.contexto.Conexao.Query<int>(query.ToString(), usuario, this.contexto.Transacao()).First();
        }

        public int AlterarSenha(int id, string senha)
        {
            RegraValidacao.VerificarValorZerado(id, "O código do usuário informado é igual a 0, nenhum registro será atualizado. Execução abortada para evitar dados inconsistentes.");
            RegraValidacao.VerificarStringVazia(senha, "A senha informada está vazia");

            int senhaAtualizada = 0;

            using (IDbCommand comando = contexto.CriarComandoBanco())
            {
                comando.CommandText = "Update Usuario Set Senha = @senha where IdUsuario = @id";
                comando.AddParameter("senha", senha);
                comando.AddParameter("id", id);

                senhaAtualizada = comando.ExecuteNonQuery();
            }

            return senhaAtualizada;
        }

        public void Ativar(int codigoUsuario)
        {
            RegraValidacao.VerificarValorZerado(codigoUsuario, "O código do usuário informado é igual a 0, nenhum registro será atualizado. Execução abortada para evitar dados inconsistentes.");

            int usuarioAtualizado = 0;

            using (IDbCommand comando = contexto.CriarComandoBanco())
            {
                comando.CommandText = "Update Usuario Set Ativo = 1 Where IdUsuario = @idUsuario";
                comando.AddParameter("idUsuario", codigoUsuario);

                comando.ExecuteNonQuery();
            }
        }

        public void Inativar(int codigoUsuario)
        {
            RegraValidacao.VerificarValorZerado(codigoUsuario, "O código do usuário informado é igual a 0, nenhum registro será atualizado. Execução abortada para evitar dados inconsistentes.");

            using (IDbCommand comando = contexto.CriarComandoBanco())
            {
                comando.CommandText = "Update Usuario Set Ativo = 0 Where IdUsuario = @idUsuario";
                comando.AddParameter("idUsuario", codigoUsuario);

                comando.ExecuteNonQuery();
            }
        }

        public Usuario BuscarUsuarioPorNome(string nome)
        {
            IList<Usuario> usuarios = this.contexto.Conexao.Query<Usuario>("select IdUsuario, Nome, UltimoLogin, Email, Ativo, DataCadastro from Usuario")
                .Where(u => u.Nome == nome).ToList();

            return usuarios.Any() ? usuarios.First() : null;            
        }

        public Usuario BuscarUsuarioPorEmail(string email)
        {
            RegraValidacao.VerificarStringVazia(email, "O email informado está vazio.");

            Usuario usuario = null;

            using (IDbCommand comando = contexto.CriarComandoBanco())
            {
                comando.CommandText = "Select IdUsuario, Nome, Email from Usuario where Email = @email";
                comando.AddParameter("email", email);

                using (IDataReader dr = comando.ExecuteReader())
                {
                    usuario = dr.ToEntity<Usuario>();
                }
            }

            return usuario;
        }

        public Usuario BuscarUsuarioPorLogin(string loginUsuario, string senha)
        {
            RegraValidacao.VerificarStringVazia(loginUsuario, "O usuario deve ser informado");
            RegraValidacao.VerificarStringVazia(senha, "A senha deve ser informada");

            StringBuilder query = new StringBuilder();
            query.Append("select IdUsuario, Nome, Email, UltimoLogin, DataCadastro, Ativo from Usuario ");
            query.Append("where Nome = @loginUsuario and senha = @senha");

            IList<Usuario> usuarios = this.contexto.Conexao.Query<Usuario>(query.ToString(), new {loginUsuario, senha}).ToList();

            return usuarios.Any() ? usuarios.First() : null;
        }


        public int BuscarCodigoUsuario(Usuario usuario)
        {
            usuario.Validar();

            int codigoUsuario = 0;

            using (IDbCommand comando = contexto.CriarComandoBanco())
            {
                comando.CommandText = "Select IdUsuario From Usuario Where Nome = @nome And Email = @email";
                comando.AddParameter("nome", usuario.Nome);
                comando.AddParameter("email", usuario.Email);

                using (IDataReader dr = comando.ExecuteReader())
                {
                    while (dr.Read())
                    {
                        if (!dr.IsDBNull(0))
                            codigoUsuario = dr.GetInt32(0);
                    }
                }
            }

            return codigoUsuario;
        }

        public int RegistrarUltimoLoginUsuario(int id)
        {
            RegraValidacao.VerificarValorZerado(id, "O código do usuário informado é igual a 0, nenhum registro será atualizado. Execução abortada para evitar dados inconsistentes.");

            int usuarioAtualizado = 0;

            using (IDbCommand comando = contexto.CriarComandoBanco())
            {
                comando.CommandText = "Update Usuario Set UltimoLogin = @ultimoLogin Where IdUsuario = @idUsuario";
                comando.AddParameter("ultimoLogin", DateTime.Now);
                comando.AddParameter("idUsuario", id);

                usuarioAtualizado = comando.ExecuteNonQuery();
            }

            return usuarioAtualizado;
        }        

        public Usuario PegarPorCodigo(int codigo)
        {
            RegraValidacao.VerificarValorZerado(codigo, "O código do usuário informado é igual a 0, nenhum registro será atualizado. Execução abortada para evitar dados inconsistentes.");

            StringBuilder query = new StringBuilder();
            query.Append("Select IdUsuario, Nome, Email from Usuario where IdUsuario = @codigo");

            return this.contexto.Conexao.Query<Usuario>(query.ToString(), new { codigo = codigo }).First();
        }

        public IEnumerable<Usuario> PegarListaCompleta()
        {
            throw new NotImplementedException();
        }

        public void Inativar(Usuario entidade)
        {
            throw new NotImplementedException();
        }
    }
}